home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / sound / sbplay25.zip / SOURCE.ZIP / _pcplay.asm < prev    next >
Assembly Source File  |  1996-01-05  |  13KB  |  415 lines

  1. _TEXT   SEGMENT WORD PUBLIC 'CODE'
  2. _TEXT   ENDS
  3.  
  4. _DATA SEGMENT WORD PUBLIC 'DATA'        
  5. _DATA   ENDS
  6.  
  7. CONST   SEGMENT WORD PUBLIC 'CONST'
  8. CONST   ENDS
  9.  
  10. _BSS    SEGMENT WORD PUBLIC 'BSS'
  11. ;GLOBAL UNINITIATED DATA GOES HERE
  12. _BSS    ENDS
  13.  
  14. DGROUP  GROUP CONST,_BSS,_DATA
  15. ;
  16.         ASSUME DS:DGROUP,SS:DGROUP
  17.  
  18. ;EXTRN EXTERNAL SUBROUTINE CALLS GO HERE
  19. ;
  20. ; _pcplay FAR Procedure for C Written by John A. Ball  January 5, 1996
  21. ;
  22. ;Plays back sound on the regular pc speaker
  23. ;
  24. ;       void     pcplay(char *buffer,unsigned number_read,unsigned frequency
  25. ;                       ,unsigned volume);
  26. ;
  27. ;       pcplay(Buffer Pointer,Length,Frequency,Volume);
  28. ;
  29. ;       Buffer Pointer is a Far pointer to the sound buffer (64k max)
  30. ;       Length is the number of sound samples to play
  31. ;       Frequency is the playback frequency in hertz
  32. ;       Volume is currently not supported
  33. ;
  34. _TEXT   SEGMENT
  35.         ASSUME CS:_TEXT
  36.         PUBLIC _pcplay
  37.                 
  38. _pcplay PROC FAR
  39.  
  40. PARMA           EQU [BP+6]      ;Sound Buffer Pointer
  41. PARMB           EQU [BP+10]     ;Number of samples to play (Length)
  42. PARMC           EQU [BP+12]     ;Frequency to playback samples
  43. PARMD           EQU [BP+14]     ;Volume 0-7
  44. PARMS           EQU 10          ;Number of bytes for local storage
  45.  
  46. BUFFERPNT       EQU [BP-4]      ;LOCAL VARIABLES GO HERE
  47. SAMPLES         EQU [BP-6]
  48. FREQUENCY       EQU [BP-8]
  49. VOLUME          EQU [BP-10]
  50.  
  51.         PUSH BP                 ;Save stack Frame
  52.         MOV BP,SP
  53.         SUB SP,PARMS            ;MAKE SPACE FOR LOCAL VARIABLE (INT) ON STACK
  54.         PUSH DS                 ;Save registers
  55.         PUSH ES
  56.         PUSH SI
  57.         PUSH DI
  58.  
  59.         JMP OVERDATA
  60.  
  61. DDELAY          DW 0
  62. TCOUNT          DW 0
  63. MCOUNT          DW 0
  64. LCOUNT          DW 0
  65. PERIOD          DW 0
  66. DOUBLER         DW 0
  67.  
  68. TABLE   DB 53,53,53,53,53,52,52,52,52,52,52,52,52,52,52,51
  69.         DB 51,51,51,51,51,51,51,51,50,50,50,50,50,50,50,50
  70.         DB 49,49,49,49,49,49,49,49,49,48,48,48,48,48,48,48
  71.         DB 48,47,47,47,47,47,47,47,46,46,46,46,46,46,46,45
  72.         DB 45,45,45,45,45,45,44,44,44,44,44,44,43,43,43,43
  73.         DB 43,43,42,42,42,42,42,42,41,41,41,41,41,40,40,40
  74.         DB 40,40,39,39,39,39,39,38,38,38,38,37,37,37,37,36
  75.         DB 36,36,35,35,35,34,34,34,33,33,32,32,31,30,29,27
  76.         DB 25,24,23,22,22,21,21,20,20,19,19,19,18,18,18,17
  77.         DB 17,17,17,16,16,16,16,15,15,15,15,14,14,14,14,14
  78.         DB 13,13,13,13,12,12,12,12,12,12,11,11,11,11,11,10
  79.         DB 10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8
  80.         DB 8,8,7,7,7,7,7,7,7,6,6,6,6,6,6,6
  81.         DB 6,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4
  82.         DB 3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2
  83.         DB 2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0
  84.  
  85. OVERDATA:
  86.         LES DI,PARMA            ;GET SOUND BUFFER POINTER
  87.         MOV BUFFERPNT,DI        ;AND SAVE
  88.         MOV DI,ES
  89.         MOV BUFFERPNT+2,DI
  90.         
  91.         MOV BX,PARMB            ;Get number of samples
  92.     CMP BX,0                ;Check for zero samples
  93.     JNE NORESET
  94.     MOV CS:DDELAY,0         ;Reset delay if zero samples
  95.     JMP FINISHED
  96. NORESET:
  97.         MOV SAMPLES,BX          ;AND SAVE
  98.  
  99.         MOV CS:DOUBLER,0
  100.         MOV BX,PARMC            ;Get frequency
  101.         CMP BX,0                ;CHECK FOR DIVIDE BY ZERO
  102.         JNE OK0
  103.         MOV BX,11000            ;use default if zero
  104. OK0:    CMP BX,0FFFFH           ;Is frequency > 32,767 hz?
  105.         JL OK21
  106.         CMP BX,15000            ;Is frequency > 15,000 hz?
  107.         JG OK1
  108.         MOV CS:DOUBLER,2        ;Indicate frequency to be doubled
  109.         SHL BX,1                ;Double frequency for play back
  110. OK1:    CMP BX,22000            ;Is frequency 22,000 hz?
  111.         JL OK2
  112. OK2:    CMP BX,0FFFFH           ;Is frequency 44,000 hz?
  113.         JG OK3
  114. OK21:   MOV CS:DOUBLER,4        ;Indicate frequency to be halved
  115.         SHR BX,1                ;Halve frequency for playback
  116. OK3:    MOV FREQUENCY,BX        ;and save
  117.         MOV DX,000FH            ;CALCULATE PERIOD 1000000/FREQUENCY
  118.         MOV AX,04240H
  119.         DIV BX
  120.         MOV CS:PERIOD,AX
  121. ;
  122. CPUSPEED:        
  123.         CMP CS:DDELAY,0         ;SKIP IF ALREADY DONE
  124.         JE GETSPEED
  125.         JMP BEGIN
  126.  
  127. GETSPEED:
  128.         IN AL,61H               ;DISCONNECT SPEAKER FROM TIMER CHIP
  129.         PUSH AX                 ;SAVE STATUS BITS
  130.         AND AL,11111100B        ;AND STOP TIMER
  131.         OUT 61H,AL
  132.         JMP $+2
  133.         JMP $+2
  134.         MOV AL,0B4H             ;PROGRAM TIMER 2 FOR MODE 2
  135.         OUT 43H,AL
  136.         JMP $+2
  137.         JMP $+2
  138.         MOV AL,0                ;SET TIMER COUNT DOWN MAX COUNT
  139.         OUT 42H,AL
  140.         JMP $+2
  141.         JMP $+2
  142.         MOV AL,00H
  143.         OUT 42H,AL
  144.         JMP $+2
  145.         JMP $+2
  146.  
  147.         POP AX                  ;START TIMER
  148.         PUSH AX
  149.         OR AL,00000001B
  150.         OUT 61H,AL
  151.         JMP $+2        
  152.         POP AX                  ;STOP TIMER
  153.         AND AL,11111100B
  154.         OUT 61H,AL
  155.         JMP $+2        
  156.         IN AL,42H               ;GET TIMER COUNT
  157.         MOV BL,AL
  158.         JMP $+2
  159.         JMP $+2
  160.         IN AL,42H
  161.         MOV BH,AL               ;BX = TIMER COUNT
  162.         MOV AX,0                ;GET NUMBER OF COUNTS USED GETTING THE TIME
  163.         SUB AX,BX
  164.         MOV CS:TCOUNT,AX        ;AND SAVE IT
  165.         
  166.         MOV SI,0
  167.         MOV DI,0
  168.         MOV CX,10               ;TIME for 10 loops
  169.  
  170.         MOV BH,0
  171.         MOV AH,0
  172.  
  173.         CLI                     ;DISABLE INTERRUPTS DURING TEST
  174.  
  175.         IN AL,61H               ;START TIMER
  176.         PUSH AX
  177.         JMP $+2
  178.         OR AL,00000001B
  179.         OUT 61H,AL
  180. ;
  181. ;USE ACTUAL LOOP FOR TIMING BUT DISABLE SPEAKER
  182. ;
  183. FETCH1:   
  184.         LDS BX,BUFFERPNT
  185.         MOV AL,[BX+SI]          ;Get sample
  186.         MOV DI,AX
  187.         MOV AL,CS:TABLE[DI]     ;and convert to 6 bits
  188.         OUT 0E0H,AL             ;use E0h so it doesn't interfere with
  189.         IN AL,0E0H
  190.         OR AL,00000000B         ;PRETEND TO START CLOCK
  191.         OUT 0E0H,AL
  192.         
  193.         PUSH CX                 ;Save number of samples
  194.         MOV CX,1                ;use minimum time
  195. DELAY1:  
  196.         JMP $+2
  197.         LOOP DELAY1
  198.         
  199.         POP CX                  ;restore sample count
  200.         INC SI
  201.         
  202.         IN AL,0E0H
  203.         AND AL,1111111B         ;PRETEND TO TURN OFF CLOCK
  204.         OUT 0E0H,AL
  205.         
  206.         LOOP FETCH1
  207.  
  208.         POP AX                  ;STOP TIMER
  209.         AND AL,11111100B
  210.         OUT 61H,AL
  211.         
  212.         STI                     ;ENABLE INTERUPTS 
  213.  
  214.         IN AL,42H               ;GET TIMER COUNT
  215.         MOV BL,AL
  216.         JMP $+2
  217.         JMP $+2
  218.         IN AL,42H
  219.         MOV BH,AL               ;BX = TIMER COUNT
  220.         MOV AX,0                ;65536 - TIMER COUNT = DURATION COUNT
  221.         SUB AX,BX
  222.         SUB AX,CS:TCOUNT        ;SUBTRACT COUNTS USED GETTING THE TIME
  223.         MOV DX,0
  224.         MOV BX,838
  225.         MUL BX                  ;COUNT X 838 / 10000 = DURATION IN uSECs 10L
  226.         MOV BX,10000
  227.         DIV BX
  228.         MOV BX,AX
  229.         MOV AX,CS:PERIOD        ;FIND OUT HOW MUCH TIME TO WASTE
  230.         SUB AL,BL
  231.         MOV AH,0
  232.         MOV CS:MCOUNT,AX        ;SAVE TIME 
  233.         
  234.         MOV CX,100              ;TIME for 100 loops
  235.         CLI                     ;DISABLE INTERRUPTS DURING TEST
  236.  
  237.         IN AL,61H               ;START TIMER 2 AGAIN
  238.         PUSH AX
  239.         JMP $+2
  240.         OR AL,00000001B
  241.         OUT 61H,AL
  242.  
  243. TIME1:  JMP $+2
  244.         LOOP TIME1
  245.  
  246.         POP AX
  247.         AND AL,11111100B
  248.         OUT 61H,AL
  249.         IN AL,42H               ;GET TIMER COUNT
  250.         MOV BL,AL
  251.         JMP $+2
  252.         JMP $+2
  253.         IN AL,42H
  254.         MOV BH,AL               ;BX = TIMER COUNT
  255.         STI
  256.         MOV DX,0
  257.         MOV AX,0                ;NOTE THAT TIMER RESTARTS AT INIT COUNT
  258.         SUB AX,BX               ;IN MODE 2
  259.         SUB AX,CS:TCOUNT        ;SUBTRACT COUNTS USED GETTING THE TIME
  260.         MOV DX,0
  261.         MOV BX,838
  262.         MUL BX                  ;COUNT X 838 / 1000 = DURATION IN uSECs 100L
  263.         MOV BX,1000
  264.         DIV BX
  265.         MOV CS:LCOUNT,AX        ;SAVE TEMPORARY VALUE
  266.         
  267.         MOV DX,0
  268.         MOV AX,CS:MCOUNT        ;GET TIME TO WASTE        
  269.         MOV BX,100
  270.         MUL BX                  ;AND MULTIPLY BY 100
  271.         MOV DX,0
  272.         MOV BX,CS:LCOUNT        ;AND DIVIDE BY LCOUNT
  273.         CMP BX,0                ;CHECK FOR DIVIDE BY ZERO
  274.         JNE OK
  275.         JMP GETSPEED            ;TRY AGAIN
  276. OK:     DIV BX                  ;TO GET LOOPS REQUIRED
  277.         AND AX,07FFH            ;LIMIT TO REASONABLE VALUE
  278.         MOV CS:DDELAY,AX        ;SAVE LOOP COUNTER VALUE
  279. BEGIN:
  280.         MOV AL,092H             ;COUNTER 2, LSB ONLY, MODE 1, BINARY
  281.         OUT 43H,AL
  282.         MOV SI,0
  283.         MOV DX,0
  284.         MOV AH,0
  285.         MOV CX,SAMPLES          ;GET NUMBER OF SAMPLES TO PLAY
  286.         cli
  287.         CMP CS:DOUBLER,0        ;ADJUST PLAYBACK?
  288.         JE FETCH
  289.         JMP BEGIN1
  290.  
  291. FETCH:   
  292.         LDS BX,BUFFERPNT
  293.         MOV DL,[BX+SI]          ;Get sample
  294.         MOV DI,DX               ;get index to table
  295.         MOV AL,CS:TABLE[DI]     ;and convert sample to timer pulse durations
  296.                                 
  297.         OUT 042H,AL
  298.         IN AL,061H
  299.         OR AL,00000011B         ;START CLOCK
  300.         OUT 061H,AL
  301.         PUSH CX                 ;Save number of samples
  302.         MOV CX,CS:DDELAY        ;GET DELAY LOOP COUNTER
  303. DELAY:  
  304.         JMP $+2
  305.         LOOP DELAY
  306.         
  307.         pop cx                  ;RESTORE SAMPLE COUNT
  308.         INC SI
  309.  
  310.         IN AL,061H
  311.         AND AL,1111110B         ;TURN OFF CLOCK
  312.         OUT 061H,AL
  313.         
  314.         LOOP FETCH              ;AND GO GET NEXT SAMPLE
  315.  
  316.         JMP FINISHED
  317.  
  318. BEGIN1:
  319.         CMP CS:DOUBLER,4       ;Halve playback?
  320.         JE PLAYHALF
  321. FETCH3:   
  322.         LDS BX,BUFFERPNT
  323.         MOV DL,[BX+SI]          ;Get sample
  324.         MOV DI,DX               ;get index to table
  325.         MOV AL,CS:TABLE[DI]     ;and convert sample to timer pulse durations
  326.                                 
  327.         OUT 042H,AL
  328.         IN AL,061H
  329.         OR AL,00000011B         ;START CLOCK
  330.         OUT 061H,AL
  331.         PUSH CX                 ;Save number of samples
  332.         MOV CX,CS:DDELAY        ;GET DELAY LOOP COUNTER
  333. DELAY3:  
  334.         JMP $+2
  335.         LOOP DELAY3
  336.         
  337.         NOP
  338.         NOP
  339.                                 
  340.         IN AL,061H
  341.         AND AL,1111110B         ;TURN OFF CLOCK
  342.         OUT 061H,AL
  343.         
  344.         LDS BX,BUFFERPNT
  345.         MOV DL,[BX+SI]          ;Get sample
  346.         MOV DI,DX               ;get index to table
  347.         MOV AL,CS:TABLE[DI]     ;and convert sample to timer pulse durations
  348.  
  349.         OUT 042H,AL             ;Output sample twice at double frequency
  350.  
  351.         IN AL,061H
  352.         OR AL,00000011B         ;START CLOCK
  353.         OUT 061H,AL
  354.  
  355.         MOV CX,CS:DDELAY        ;GET DELAY LOOP COUNTER
  356. DELAY4:  
  357.         JMP $+2
  358.         LOOP DELAY4
  359.         
  360.         pop cx                  ;RESTORE SAMPLE COUNT
  361.         INC SI
  362.  
  363.         IN AL,061H
  364.         AND AL,1111110B         ;TURN OFF CLOCK
  365.         OUT 061H,AL
  366.         
  367.         LOOP FETCH3             ;AND GO GET NEXT SAMPLE
  368.         
  369.         JMP FINISHED
  370.  
  371. PLAYHALF:   
  372.         SHR CX,1                ;Halve the number of samples
  373. FETCH4:
  374.         LDS BX,BUFFERPNT
  375.         MOV DL,[BX+SI]          ;Get sample
  376.         MOV DI,DX               ;get index to table
  377.         MOV AL,CS:TABLE[DI]     ;and convert sample to timer pulse durations
  378.                                 
  379.         OUT 042H,AL
  380.         IN AL,061H
  381.         OR AL,00000011B         ;START CLOCK
  382.         OUT 061H,AL
  383.         PUSH CX                 ;Save number of samples
  384.         MOV CX,CS:DDELAY        ;GET DELAY LOOP COUNTER
  385. DELAY5:  
  386.         JMP $+2
  387.         LOOP DELAY5
  388.         
  389.         pop cx                  ;RESTORE SAMPLE COUNT
  390.         INC SI                  ;Increment twice to skip sample
  391.         INC SI
  392.  
  393.         IN AL,061H
  394.         AND AL,1111110B         ;TURN OFF CLOCK
  395.         OUT 061H,AL
  396.         
  397.         LOOP FETCH4             ;AND GO GET NEXT SAMPLE
  398.  
  399. FINISHED:        
  400.  
  401.         sti
  402.     MOV AX,0                ;Indicate no error
  403.         POP DI
  404.         POP SI
  405.         POP ES                  ;Restore registers
  406.         POP DS
  407.         ADD SP,PARMS            ;RESTORE SP
  408.         POP BP                  ;RESTORE BP
  409.         RET                     ;RETURN FAR
  410.  
  411. _pcplay  ENDP
  412. _TEXT   ENDS        
  413.         END
  414.  
  415.